package com.github.ecbp.common.data.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.github.ecbp.common.api.CommonPage;
import com.github.ecbp.common.data.builder.CommonPageBuilder;
import com.github.ecbp.common.data.entity.BaseEntity;
import com.github.ecbp.common.data.mapper.BaseMapper;
import com.github.ecbp.common.data.service.BaseService;
import com.github.ecbp.common.data.utils.CommonCodeAndMessageEnum;
import com.github.ecbp.common.data.utils.PagingUtil;
import com.github.ecbp.common.data.utils.TransformUtils;
import com.github.ecbp.common.req.BaseIdListDTO;
import com.github.ecbp.common.req.BasePageDTO;
import com.github.ecbp.common.resp.NameVo;
import com.github.ecbp.common.utils.Asserts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.List;

public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BaseService<T> {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 使用反射技术得到T的真实类型
     *
     * @return
     */
    protected Class<T> getEntityClass() {
        // 获取当前new的对象的泛型的父类类型
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        // 获取第一个类型参数的真实类型
        return (Class<T>) pt.getActualTypeArguments()[1];
    }

    @Override
    public IPage<T> page(T entity) {
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>(getEntityClass());
        assemble(entity, wrapper);
        return super.page(new Page<>(PagingUtil.getPage(), PagingUtil.getLimit()), wrapper);
    }

    @Override
    public <VO> IPage<VO> page(Object param, Class<VO> targetClass) {
        T entity = TransformUtils.copy(param, getEntityClass());
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>(getEntityClass());
        if (param instanceof BasePageDTO) {
            assemble(entity, wrapper, (BasePageDTO) param);
        } else {
            assemble(entity, wrapper);
        }
        return CommonPageBuilder.buildPageInfo(baseMapper.selectPage(new Page<>(PagingUtil.getPage(), PagingUtil.getLimit()), wrapper), targetClass);
    }

    /***
     * @Description: 通过IDs获取
     * @param param
     * @return: java.util.List<T>
     * @Author: zj2626
     * @Date: 2020/5/11
     */
    @Override
    public List<T> getByIds(BaseIdListDTO param) {
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>(getEntityClass());
        wrapper.in(T::getId, param.getIds());
        return baseMapper.selectList(wrapper);
    }

    /***
     * @Description: 通过IDs获取id和名字
     * @param param
     * @Author: zj2626
     * @Date: 2020/5/11
     */
    @Override
    public List<NameVo> getIdAndNameByIds(BaseIdListDTO param) {
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>(getEntityClass());
        wrapper.in(T::getId, param.getIds());
        return TransformUtils.listCopy(baseMapper.selectList(wrapper), NameVo.class);
    }

    /***
     * @Description: 下拉数据获取
     * @Author: zj2626
     * @Date: 2020/5/11
     */
    @Override
    public List<NameVo> listIdAndName() {
        final QueryWrapper<T> wrapper = new QueryWrapper<>();
        wrapper.select("id", "name");
        wrapper.eq("status", 1);
        return TransformUtils.listCopy(baseMapper.selectList(wrapper), NameVo.class);
    }

    @Override
    public boolean saveBase(Object param) {
        T entity = TransformUtils.copy(param, getEntityClass());
        Asserts.isTrue(super.save(entity), CommonCodeAndMessageEnum.SAVE_ERROR);
        return true;
    }

    @Override
    public boolean saveOrUpdateBase(Object param) {
        T entity = TransformUtils.copy(param, getEntityClass());
        Asserts.isTrue(super.saveOrUpdate(entity), CommonCodeAndMessageEnum.SAVE_ERROR);
        return true;
    }

    @Override
    public boolean saveBatchBase(List<Object> param) {
        List<T> entityList = TransformUtils.listCopy(param, getEntityClass());
        Asserts.isTrue(super.saveBatch(entityList), CommonCodeAndMessageEnum.SAVE_ERROR);
        return true;
    }

    @Override
    public boolean saveOrUpdateBatchBase(List<Object> param) {
        List<T> entityList = TransformUtils.listCopy(param, getEntityClass());
        Asserts.isTrue(super.saveOrUpdateBatch(entityList), CommonCodeAndMessageEnum.UPDATE_ERROR);
        return true;
    }

    @Override
    public boolean updateByIdBase(Object param) {
        T entity = TransformUtils.copy(param, getEntityClass());
        Asserts.isTrue(super.updateById(entity), CommonCodeAndMessageEnum.UPDATE_ERROR);
        return true;
    }

    @Override
    public boolean updateBatchByIdBase(List<Object> param) {
        List<T> entityList = TransformUtils.listCopy(param, getEntityClass());
        Asserts.isTrue(super.updateBatchById(entityList), CommonCodeAndMessageEnum.UPDATE_ERROR);
        return true;
    }

    @Override
    public boolean removeById(Serializable id) {
        try {
            T entity = getEntityClass().newInstance();
            entity.setId((Long) id);
            return SqlHelper.retBool(baseMapper.deleteByIdWithFill(entity));
        } catch (Exception e) {
            logger.error("删除异常", e);
        }
        return false;
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return false;
        }
        try {
            T entity = getEntityClass().newInstance();
            return SqlHelper.retBool(getBaseMapper().deleteBatchByIdsWithFill(entity, idList));
        } catch (Exception e) {
            logger.error("删除异常", e);
        }
        return false;
    }

    @Override
    public final boolean remove(Wrapper<T> wrapper) {
        try {
            T entity = getEntityClass().newInstance();
            return SqlHelper.retBool(baseMapper.deleteWithFill(entity, wrapper));
        } catch (Exception e) {
            logger.error("删除异常", e);
        }
        return false;
    }

    @Override
    public boolean removeByIdBase(Serializable id) {
        Asserts.isTrue(removeById(id), CommonCodeAndMessageEnum.DELETE_ERROR);
        return true;
    }

    @Override
    public boolean removeBase(Wrapper<T> wrapper) {
        Asserts.isTrue(remove(wrapper), CommonCodeAndMessageEnum.DELETE_ERROR);
        return true;
    }

    protected void assemble(Object obj, LambdaQueryWrapper<T> wrapper) {
        T entity = TransformUtils.copy(obj, getEntityClass());
        assemble(entity, wrapper);
    }

    protected void assemble(T entity, LambdaQueryWrapper<T> wrapper) {
        if (null != entity.getId()) {
            wrapper.eq(T::getId, entity.getId());
        }
        // then do nothing
    }

    protected void assemble(T entity, LambdaQueryWrapper<T> wrapper, BasePageDTO pageDTO) {
        assemble(entity, wrapper);

        if (null != pageDTO) {
            if (null != pageDTO.getStartDate()) {
                wrapper.ge(T::getCreateTime, pageDTO.getStartDate());
            }
            if (null != pageDTO.getEndDate()) {
                wrapper.le(T::getCreateTime, pageDTO.getEndDate());
            }
        }
        // then do nothing
    }
}